package cn.admin.configcenter.address;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.regex.Pattern;

public class AddressServerIpHolder {

	private static Logger LOG = LoggerFactory.getLogger(AddressServerIpHolder.class);
	private static final String ADDRESS_SERVER_IP_PROPERTY_NAME = "address.server.ip";
	private static Pattern IPV4RegexPattern = Pattern.compile("^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
	private static final String ADDRESS_SERVER_IP = getAddressServerIpInterval();

	public static String getAddressServerIp() {
		return ADDRESS_SERVER_IP;
	}

	private static String getAddressServerIpInterval() {
		try {
			String addressServerIp = System.getProperty(ADDRESS_SERVER_IP_PROPERTY_NAME);
			return addressServerIp != null && validate(addressServerIp) ? addressServerIp : getPublicIPv4();
		} catch (Exception e) {
			LOG.error("find address server ip failed.");
			throw new RuntimeException(e);
		}
	}

	private static String getPublicIPv4() throws SocketException {
		Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
		while (true) {
			NetworkInterface networkInterface;
			do {
				if (!networkInterfaces.hasMoreElements()) {
					return null;
				}
				networkInterface = networkInterfaces.nextElement();
			} while (!validate(networkInterface));

			Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
			while (inetAddresses.hasMoreElements()) {
				InetAddress inetAddress = inetAddresses.nextElement();
				String currentAddress = inetAddress.getHostAddress();
				LOG.debug("IP address " + currentAddress + " found");
				if (validate(currentAddress)) {
					return currentAddress;
				}
			}
		}
	}

	private static boolean validate(NetworkInterface networkInterface) throws SocketException {
		return !networkInterface.isLoopback() && !networkInterface.isVirtual() && networkInterface.isUp();
	}

	private static boolean validate(String ip) {
		return IPV4RegexPattern.matcher(ip).matches();
	}

}
